package tech.heiming.aps.scheduler.deadline;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
import org.optaplanner.core.api.domain.variable.PlanningVariable;
import tech.heiming.aps.scheduler.domain.*;
import tech.heiming.aps.scheduler.enums.ShiftType;

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author heimingz
 */
@Slf4j
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@PlanningEntity
public class OrderSlice {
    public static final int LIMIT = 1;
    public static final ResourceGroup NULL_TEAM = new ResourceGroup("null", "null", 0L, Collections.emptyList());
    public static final Equipment NULL_EQUIPMENT = new Equipment("null", "null", null);

    /**
     * 格式：订单编号_订单切分编号/最大订单切分编号_工艺序号/最大工艺序号
     * 每个工艺步骤下订单切分的粒度不同
     */
    private String id;

    private Order order;

    private Product product;

    private Craft craft;

    private LocalDateTime scheduleStartTime;

    @PlanningVariable(valueRangeProviderRefs = "employeeArrangementRange")
    private EmployeeArrangement employees;

    @PlanningVariable(valueRangeProviderRefs = "equipmentRange")
    private Resource equipments;

    @PlanningVariable(valueRangeProviderRefs = "timeslotRange")
    private Long startTimeslot;

//    @PlanningVariable(valueRangeProviderRefs = "timeslotRange")
//    private Long endTimeslot;

    public OrderSlice(String id, Order order, Product product, Craft craft, LocalDateTime scheduleStartTime) {
        this.id = id;
        this.order = order;
        this.product = product;
        this.craft = craft;
        this.scheduleStartTime = scheduleStartTime;
    }

    @ValueRangeProvider(id = "employeeArrangementRange")
    public List<EmployeeArrangement> getEmployeeRange() {
        if (craft.getProdTeamDescription() == null) {
            return Collections.singletonList(new EmployeeArrangement(Collections.singletonList(NULL_TEAM)));
        }
        return EmployeeArrangement.getCandidates(craft.getRequiredEmployeeAmount(),
                new ArrayList<>(craft.getProdTeamDescription().keySet()));
    }

    @ValueRangeProvider(id = "equipmentRange")
    public List<Resource> getEquipmentRange() {
        if (craft.getEquipmentGrpDescription() == null) {
            return Collections.singletonList(NULL_EQUIPMENT);
        }
        return craft.getEquipmentGrpDescription().keySet().stream()
                .filter(Objects::nonNull)
                .flatMap(resourceGroup -> resourceGroup.getResources().stream())
                .collect(Collectors.toList());
    }

    public Integer getOrderId() {
        String str1 = id.substring(0, id.indexOf("_"));
        String str2 = id.substring(id.indexOf("_") + 1, id.lastIndexOf("_"));
        String str3 = id.substring(id.lastIndexOf("_") + 1);
        return Integer.parseInt(str1);
    }

    public Integer getItemIndex() {
        String str1 = id.substring(0, id.indexOf("_"));
        String str2 = id.substring(id.indexOf("_") + 1, id.lastIndexOf("_"));
        String str3 = id.substring(id.lastIndexOf("_") + 1);
        return Integer.parseInt(str2.substring(0, str2.indexOf("/")));
    }

    public boolean isLastItem() {
        String str1 = id.substring(0, id.indexOf("_"));
        String str2 = id.substring(id.indexOf("_") + 1, id.lastIndexOf("_"));
        String str3 = id.substring(id.lastIndexOf("_") + 1);
        int num1 = Integer.parseInt(str2.substring(0, str2.indexOf("/")));
        int num2 = Integer.parseInt(str2.substring(str2.indexOf("/") + 1));
        return num1 == num2;
    }

    public Integer getCraftIndex() {
        String str1 = id.substring(0, id.indexOf("_"));
        String str2 = id.substring(id.indexOf("_") + 1, id.lastIndexOf("_"));
        String str3 = id.substring(id.lastIndexOf("_") + 1);
        return Integer.parseInt(str3.substring(0, str2.indexOf("/")));
    }

    public boolean isLastCraft() {
        String str1 = id.substring(0, id.indexOf("_"));
        String str2 = id.substring(id.indexOf("_") + 1, id.lastIndexOf("_"));
        String str3 = id.substring(id.lastIndexOf("_") + 1);

        int num1 = Integer.parseInt(str3.substring(0, str2.indexOf("/")));
        int num2 = Integer.parseInt(str3.substring(str2.indexOf("/") + 1));
        if (num1 == num2) {
            return true;
        }
        return false;
    }

    public boolean shiftCraftTimeConflict() {
        LocalDateTime tmpStart = scheduleStartTime.plusSeconds(startTimeslot * 60 * 60 * 12);
        LocalDateTime tmpEnd = scheduleStartTime.plusSeconds((startTimeslot + LIMIT - 1 + 1) * 60 * 60 * 12);
        if (employees != null && employees.getEmployeeGroups() != null) {
            List<ResourceGroup> mlist1 = employees.getEmployeeGroups();
            for (int i = 0; i < mlist1.size(); i++) {
                ResourceGroup rg = mlist1.get(i);
                if (nullTeam.equals(rg)) continue;
                List<Resource> mlist2 = rg.getResources();
                for (int j = 0; j < mlist2.size(); j++) {
                    Resource re = mlist2.get(j);
                    Shift shift = re.getShift();
                    if (shift.getDayOfWeeks() == null) {
                        log.error(re.toString());
                    }
                    for (Map.Entry<DayOfWeek, ShiftType> entry : shift.getDayOfWeeks().entrySet()) {
                        if (tmpStart.getDayOfWeek().equals(entry.getKey()) && tmpEnd.getDayOfWeek().equals(entry.getKey())) {
                            if (entry.getValue().equals(ShiftType.REST)) {//休息则冲突
                                return true;
                            } else if (entry.getValue().equals(ShiftType.ALL_DAY)) {
                                continue;
                            } else if (entry.getValue().equals(ShiftType.MORNING)) {
                                if (tmpStart.getHour() < 7 || tmpEnd.getHour() > 19 || (tmpEnd.getHour() == 19 && tmpEnd.getMinute() != 0)) {
                                    return true;
                                }
                            } else if (entry.getValue().equals(ShiftType.EVENING)) {
                                if (tmpStart.getHour() < 19 && tmpStart.getHour() >= 7) {
                                    return true;
                                }
                                if (tmpEnd.getHour() < 19 && tmpEnd.getHour() >= 7) {
                                    return true;
                                }
                            }
                        } else if (tmpStart.getDayOfWeek().equals(entry.getKey())) {
                            if (entry.getValue().equals(ShiftType.REST)) {//休息则冲突
                                return true;
                            } else if (entry.getValue().equals(ShiftType.ALL_DAY)) {
                                continue;
                            } else if (entry.getValue().equals(ShiftType.MORNING)) {
                                return true;
                            } else if (entry.getValue().equals(ShiftType.EVENING)) {
                                if (tmpStart.getHour() < 19) {
                                    return true;
                                }
                            }

                        } else if (tmpEnd.getDayOfWeek().equals(entry.getKey())) {
                            if (entry.getValue().equals(ShiftType.REST)) {//休息则冲突
                                return true;
                            } else if (entry.getValue().equals(ShiftType.ALL_DAY)) {
                                continue;
                            } else if (entry.getValue().equals(ShiftType.MORNING)) {
                                return true;
                            } else if (entry.getValue().equals(ShiftType.EVENING)) {
                                if (tmpEnd.getHour() > 7 || (tmpEnd.getHour() == 7 && tmpEnd.getMinute() != 0)) {
                                    return true;
                                }
                            }

                        } else {
                            continue;
                        }

                    }
                }
            }
        }
        if (equipments != null && !equipments.equals(nullEquipment)){
            Shift shift = equipments.getShift();
            for (Map.Entry<DayOfWeek, ShiftType> entry : shift.getDayOfWeeks().entrySet()) {
                if (tmpStart.getDayOfWeek().equals(entry.getKey()) && tmpEnd.getDayOfWeek().equals(entry.getKey())) {
                    if (entry.getValue().equals(ShiftType.REST)) {//休息则冲突
                        return true;
                    } else if (entry.getValue().equals(ShiftType.ALL_DAY)) {
                        continue;
                    } else if (entry.getValue().equals(ShiftType.MORNING)) {
                        if (tmpStart.getHour() < 7 || tmpEnd.getHour() > 19 || (tmpEnd.getHour() == 19 && tmpEnd.getMinute() != 0)) {
                            return true;
                        }
                    } else if (entry.getValue().equals(ShiftType.EVENING)) {
                        if (tmpStart.getHour() < 19 && tmpStart.getHour() >= 7) {
                            return true;
                        }
                        if (tmpEnd.getHour() < 19 && tmpEnd.getHour() >= 7) {
                            return true;
                        }
                    }
                } else if (tmpStart.getDayOfWeek().equals(entry.getKey())) {
                    if (entry.getValue().equals(ShiftType.REST)) {//休息则冲突
                        return true;
                    } else if (entry.getValue().equals(ShiftType.ALL_DAY)) {
                        continue;
                    } else if (entry.getValue().equals(ShiftType.MORNING)) {
                        return true;
                    } else if (entry.getValue().equals(ShiftType.EVENING)) {
                        if (tmpStart.getHour() < 19) {
                            return true;
                        }
                    }

                } else if (tmpEnd.getDayOfWeek().equals(entry.getKey())) {
                    if (entry.getValue().equals(ShiftType.REST)) {//休息则冲突
                        return true;
                    } else if (entry.getValue().equals(ShiftType.ALL_DAY)) {
                        continue;
                    } else if (entry.getValue().equals(ShiftType.MORNING)) {
                        return true;
                    } else if (entry.getValue().equals(ShiftType.EVENING)) {
                        if (tmpEnd.getHour() > 7 || (tmpEnd.getHour() == 7 && tmpEnd.getMinute() != 0)) {
                            return true;
                        }
                    }

                } else {
                    continue;
                }

            }
        }
        return false;
    }
}
